package com.xxx.service.impl;

import com.xxx.domain.KillActivity;
import com.xxx.domain.KillCourse;
import com.xxx.dto.PreCourseOrder2RedisDto;
import com.xxx.mapper.KillCourseMapper;
import com.xxx.service.IKillActivityService;
import com.xxx.service.IKillCourseService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.xxx.util.AssertUtil;
import com.xxx.util.CodeGenerateUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jh
 * @since 2025-09-16
 */
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {
    /**
     * activityId
     * KillCount
     * killPrice
     * 条件判断
     * 活动存在处于未发布状态
     * 设置初始值,保存即可
     *
     * @param entity
     * @return
     */
    @Autowired
    private IKillActivityService killActivityService;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public boolean insert(KillCourse entity) {

        KillActivity killActivity = killActivityService.selectById(entity.getActivityId());
        AssertUtil.isNotNull(killActivity, "秒杀活动不存在");
        AssertUtil.isEquals(killActivity.getPublishStatus(), KillActivity.PUBLISH_STATUS_WAIT,
                "秒杀活动未发布状态下才能添加课程");
        entity.setCreateTime(new Date());
        entity.setKillLimit(1);
        entity.setKillSort(0);
        entity.setPublishStatus(KillCourse.PUBLISH_STATUS_WAIT);
        entity.setStartTime(killActivity.getBeginTime());
        entity.setEndTime(killActivity.getEndTime());
        entity.setTimeStr(killActivity.getTimeStr());
        return super.insert(entity);
    }

    /**
     * 获取所有已经发布的课程
     *
     * @return
     */
    @Override
    public List<KillCourse> onlineAll() {
        Set<Object> keys = redisTemplate.keys("activity:*");
        List<KillCourse> killCourses = new ArrayList<>();
        keys.forEach(key -> {
            List values = redisTemplate.opsForHash().values(key);
            killCourses.addAll(values);
        });
        return killCourses;
    }

    /**
     * 获取一个秒杀课程
     *
     * @param activityId
     * @param courseId
     * @return
     */
    @Override
    public KillCourse onlineOne(Long activityId, Long courseId) {
        Object o = redisTemplate.opsForHash().get("activity:" + activityId, "activityId:" + activityId + ":" +
                "courseId:" + courseId);
        AssertUtil.isNotNull(o, "该秒杀课程信息不存在");
        //强转
        KillCourse killCourse = (KillCourse) o;
        return killCourse;
    }

    /**
     * 条件判断
     * 秒杀课程存在
     * 正在秒杀中
     * 秒杀课程库存数量>0
     * 当前用户值是否秒杀过
     * 扣减库存
     * 生成宇创订单,保存到Redis
     * 返回订单号
     *
     * @param activityId
     * @param courseId
     * @return
     */
    @Override
    public String kill(Long activityId, Long courseId) {
        Long longinId = 3L; //TODO
        //* 条件判断
        //*  秒杀课程存在
        KillCourse killCourse = onlineOne(activityId, courseId);
        //*  正在秒杀中
        AssertUtil.isTrue(killCourse.isKilling(), "该秒杀课程已结束");
        //*  当前用户值是否秒杀过 //todo
        String recordeKey = "recorde:" + longinId + ":" + activityId + ":" + courseId;
        Object recordeResult = redisTemplate.opsForValue().get(recordeKey);
        AssertUtil.isNull(recordeResult, "您已秒杀过该课程");
        //* 扣减库存,减信号量
        RSemaphore semaphore = redissonClient.getSemaphore("activityId:" + activityId + ":" +
                "courseId:" + courseId);
        //扣减信号量
        Integer limitCount = 1;
        boolean b = semaphore.tryAcquire(limitCount);
        AssertUtil.isTrue(b, "手速太慢了,秒杀课程已售完");
        //* 生成宇创订单,保存到Redis
        PreCourseOrder2RedisDto preCourseOrder2RedisDto = new PreCourseOrder2RedisDto(
                CodeGenerateUtils.generateOrderSn(longinId),
                killCourse.getKillPrice(),
                limitCount,
                longinId,
                killCourse.getCourseId(),
                killCourse.getCourseName(),
                killCourse.getCoursePic()
        );
        //设置key
        String preCourseOrderKey = "preCourseOrder:" + longinId + ":" + preCourseOrder2RedisDto.getOrderNo();
        //保存
        redisTemplate.opsForValue().set(preCourseOrderKey, preCourseOrder2RedisDto);
        //保存当前用户的购买标识,活动结束自动到期删除
        Long expireTime = killCourse.getEndTime().getTime() - new Date().getTime();
        redisTemplate.opsForValue().set(recordeKey, limitCount, expireTime, TimeUnit.MILLISECONDS);
        //发送mq延迟消息 检查后续用户是否将下单和支付流程走完如果没有走完 就要退库存
        rocketMQTemplate.syncSend(
                "kill-course-order:kill",
                null,
                1000,
                3
        );
















        //* 返回订单号
        return preCourseOrder2RedisDto.getOrderNo();
    }
}
